<?php

namespace App\Ship\Criterias;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Http\Request;
use Prettus\Repository\Contracts\CriteriaInterface;
use Prettus\Repository\Contracts\RepositoryInterface;
use Str;


class OrderByCriteria implements CriteriaInterface
{

    /**
     * @var Request
     */
    protected Request $request;

    public function __construct(Request $request)
    {
        $this->request = $request;
    }

    public function apply($model, RepositoryInterface $repository)
    {
        $orderBy = $this->request->get(config('repository.criteria.newParams.orderBy', 'orderBy'), null);
        $sortedBy = $this->request->get(config('repository.criteria.newParams.sortedBy', 'sortedBy'), 'asc');

        if (empty($orderBy)) {
            return $model;
        }

        $orderBySplit = explode(';', $orderBy);
        if (count($orderBySplit) > 1) {
            $sortedBySplit = explode(';', $sortedBy);
            foreach ($orderBySplit as $orderBySplitItemKey => $orderBySplitItem) {
                $sortedBy = $sortedBySplit[$orderBySplitItemKey] ?? $sortedBySplit[0];
                $model = $this->parserFieldsOrderBy($model, $orderBySplitItem, $sortedBy);
            }
        } else {
            return $this->parserFieldsOrderBy($model, $orderBySplit[0], $sortedBy);
        }

        return $model;
    }

    protected function parserFieldsOrderBy($model, $orderBy, $sortedBy)
    {
        $split = explode('.', $orderBy);
        if (count($split) > 1) {
            $table = $model;
            foreach ($split as $splitItemKey => $splitItem) {
                if ($splitItemKey === array_key_last($split)) {
                    $column = $table->getModel()->getTable() . "." . $splitItem;
                    $model = $model->orderBy($column, $sortedBy);
                } else {
                    $relation = $table->getRelation($splitItem);
                    $sortTable = $relation->getModel()->getTable();

                    if (implode("_", explode("_", $relation->getForeignKeyName(), -1)) === Str::singular($table->getModel()->getTable())) {
                        $first = $table->getModel()->getTable() . "." . $relation->getModel()->getKeyName();
                        $second = $sortTable . "." . $relation->getForeignKeyName();
                    } else {
                        $first = $table->getModel()->getTable() . "." . $relation->getForeignKeyName();
                        $second = $sortTable . "." . $relation->getModel()->getKeyName();
                    }

                    $joins = $model->getQuery()->joins ?? [];
                    foreach ($joins as $join) {
                        if ($join->type === 'left' && $join->table === $sortTable) {
                            break 2;
                        }
                    }

                    $model = $model->leftJoin($sortTable, $first, '=', $second);


                    $table = $relation;
                }
            }

            $model = $model->addSelect($model->getModel()->getTable() . '.*');
        } else {
            $model = $model->orderBy($orderBy, $sortedBy);
        }
        return $model;
    }
}
